///<reference path="../typings/tsd.d.ts" />
/*使用说明
自动计时以及点击后禁止按钮，防止重复上报的功能。通常可以结合使用
$("#btn").ajaxButton(function(){
    $("span").autoTimer();
    return $.ajax("url").always(function(){
        $("span").autoTimer("pause");
    });
});
ajaxButton必须传入一个函数。函数必须返回一个$.deffer
*/
var AUTO;
(function (AUTO) {
    var AjaxButton = (function () {
        function AjaxButton(element, fun_def, fun_para) {
            var me = $(this);
            me.off("click").on('click', function (event) {
                if (me.hasClass('disabled'))
                    return;
                me.addClass('disabled ');
                fun_def(fun_para).always(function () {
                    me.removeClass('disabled ');
                });
            });
        }
        return AjaxButton;
    }());
    AUTO.AjaxButton = AjaxButton;
    var AutoTimer = (function () {
        function AutoTimer(element, options) {
            this.cmd = { run: this.run, pause: this.pause, reset: this.reset };
            this.$el = $(element);
            //如果是调用, 不传参，或传入一个object
            if (_.isUndefined(options) || _.isObject(options)) {
                this.opt = {
                    text: '已执行<%=time%>秒。',
                    interval: 1000 //默认间隔1秒
                };
                $.extend(this.opt, options);
                this.opt.count = 1;
                this.tmpl = _.template(this.opt.text);
                this.opt.timer = setInterval(this.render.bind(this), this.opt.interval);
                this.$el.data('options', this);
            }
            else {
                //否则传入的是一个命令
                var me = this.$el.data('options');
                me.cmd[options].call(me);
            }
        }
        // 输出内容
        AutoTimer.prototype.render = function () {
            this.$el.html(this.tmpl({ time: this.opt.count++ }));
        };
        AutoTimer.prototype.pause = function () {
            if (this.opt.timer) {
                clearInterval(this.opt.timer);
                this.opt.timer = null;
            }
        };
        AutoTimer.prototype.run = function () {
            if (!this.opt.timer) {
                this.opt.timer = setInterval(this.render.bind(this), this.opt.interval);
            }
        };
        AutoTimer.prototype.reset = function () {
            if (this.opt.timer) {
                clearInterval(this.opt.timer);
                this.opt.timer = null;
                this.opt.count = 0;
                this.render();
            }
        };
        return AutoTimer;
    }());
    AUTO.AutoTimer = AutoTimer;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
/*使用说明
该功能弹出对话框，基于layer的一个包装。
$('div').dialog(options: ILayerOption)
或者关闭它 $('div').dialog('close')
*/
var AUTO;
(function (AUTO) {
    var Dialog = (function () {
        function Dialog(element, options) {
            this._$el = $(element);
            if (_.isObject(options)) {
                this._opt = $.extend({
                    type: 1,
                    content: this._$el,
                    maxmin: true //默认最大化
                }, options);
                var index = layer.open(this._opt);
                this._$el.data("dialogindex", index);
            }
            else if (_.isString(options)) {
                //目前仅支持close一个命令
                if (options == "close") {
                    layer.close(this._$el.data("dialogindex"));
                }
            }
        }
        return Dialog;
    }());
    AUTO.Dialog = Dialog;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
/*使用说明
该功能设置年，月，日的日期框，基于bs-datepicker插件，特殊处理了一下201606这种格式，原插件不支持它的日期识别。
$("input").autoDate('ny') ;
如果要扩展默认功能，在第2个参数定义DatepickerOptions的各个属性
*/
var AUTO;
(function (AUTO) {
    var DateBox = (function () {
        function DateBox(element, mode, options) {
            var info = {
                "n": { format: 'yyyy', startView: 2, minViewMode: 2 },
                "ny": { format: 'yyyymm', startView: 1, minViewMode: 1 },
                "nyr": { format: 'yyyy-mm-dd', startView: 0, minViewMode: 0 }
            };
            this._$el = $(element);
            this._opt = $.extend({
                weekStart: 1,
                autoclose: true,
                useCurrent: false,
                orientation: 'left bottom',
                language: 'zh-CN'
            }, info[mode], options);
            this._$el.datepicker(this._opt);
            //如果是年月时，处理一下。
            if (mode == 'ny') {
                var v = this._$el.val();
                if (v && (/\d{6}/).test(v)) {
                    v = v.substr(0, 4) + "/" + v.substr(4);
                    this._$el.datepicker('setDate', new Date(v));
                }
            }
        }
        return DateBox;
    }());
    AUTO.DateBox = DateBox;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
/*使用说明
该功能自动选择input中的全部文字，是辅助autotable的一个方法
$('#input').selectWord()
*/
var AUTO;
(function (AUTO) {
    var SelectWord = (function () {
        function SelectWord(element) {
            var length = element.value.length;
            if (element.setSelectionRange) {
                element.focus();
                element.setSelectionRange(0, length);
            }
            else if (element.createTextRange) {
                var range = element.createTextRange();
                range.collapse(true);
                range.moveEnd('character', length);
                range.moveStart('character', 0);
                range.select();
            }
        }
        return SelectWord;
    }());
    AUTO.SelectWord = SelectWord;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
var AUTO;
(function (AUTO) {
    (function (SelectMode) {
        SelectMode[SelectMode["NONE"] = 0] = "NONE";
        SelectMode[SelectMode["SINGLE"] = 1] = "SINGLE";
        SelectMode[SelectMode["MULTI"] = 2] = "MULTI";
    })(AUTO.SelectMode || (AUTO.SelectMode = {}));
    var SelectMode = AUTO.SelectMode;
    var AutoTable = (function () {
        function AutoTable(element, options) {
            this._opt = {
                data: [],
                prefix: '',
                isRownumber: false,
                header: [],
                header2: [],
                headerFields: [],
                header2Fields: [],
                isFooter: true,
                zeroShowAs: '0',
                nullShowAs: '',
                isPageable: false,
                pageNumber: 1,
                pageSize: 20,
                pageSizeList: [10, 20, 50, 100],
                sortFields: [],
                mergeFields: [],
                columnsWidths: [],
                isScrollable: false,
                freezeFields: [],
                freezeContainer: window,
                selectMode: SelectMode.MULTI,
                columns: {},
                tooltipOnRow: null,
                keydataOnRow: [],
                editUrl: '',
                editTable: '',
                editKeyFields: [],
                editFields: [],
                editOn: null,
                editBeforeUpload: null,
                editTopHover: false,
                filter: null,
                isSaveable: false,
                saveURL: "",
                treeIndentOn: null,
                treeField: "",
                treeIndentShowLevel: 1,
                treeStartOn: null,
                initClass: "table table-striped table-bordered table-condensed table-hover"
            };
            this.prefix = "";
            this.thead = "";
            this.tbody = "";
            this.tfoot = "";
            this.thead2 = "";
            this.tbody2 = "";
            this.tcolgroup = ""; //控制列宽
            /**字段字典         */
            this.fieldsDict = {};
            /**保存目前的排序信息 */
            this.sortInfo = {};
            this.hidedFields = [];
            this.me = $(element);
            this._opt = $.extend(this._opt, options);
            this.prefix = (this._opt.prefix || this.me.attr("id") || ("auto")) + "_";
            this.init();
            this.renderColgroup(); //只生成一次
            this.renderThead(); //只生成一次
            this.renderTfoot();
            this.renderTbody();
            this.me.html(this.tcolgroup + "<tbody>" + (this.tbody + this.thead2 + this.tbody2) + "</tbody>" + this.thead + "<tfoot>" + this.tfoot + "</tfoot>");
            this.findDoms();
            this.readHeadIndex();
            //这些方法只绑定一次即可
            this.bindEvents();
            this.me.data('OriginData', this).trigger('loaded');
        }
        AutoTable.prototype.reloadTbodyTfoot = function () {
            this.renderTfoot();
            this.renderTbody();
            this.me.find("tbody").html(this.tbody + this.thead2 + this.tbody2);
            this._opt.isFooter && this.me.find("tfoot").html(this.tfoot);
            this.findDoms();
            this.me.trigger("reloaded");
        };
        //递归排序所有的行。
        AutoTable.prototype.rec_Treerows = function (parentRow, remainedRow, sortedRow) {
            var scope = this;
            _.each(remainedRow, function (r, idx) {
                //如果已经标记过，则跳过它。
                if (r["_isMarked"])
                    return true;
                //如果该行是子级行，则压入，继续递归找该行的子组
                if (scope._opt.treeIndentOn(parentRow, r)) {
                    r["_isMarked"] = true;
                    sortedRow.push(r);
                    scope.rec_Treerows(r, remainedRow, sortedRow);
                }
            });
        };
        AutoTable.prototype.init = function () {
            var scope = this;
            //1、是不是第一次调此函数。不是则添加样式，是则移除原事件.
            if (this.me.hasClass(AutoTable.DefaultClassName)) {
                this.me.off(AutoTable.DefaultEventNamespace);
                this.me.data("OriginData").tContainer.off(AutoTable.DefaultEventNamespace);
            }
            else {
                this.me.addClass(AutoTable.DefaultClassName + " " + this._opt.initClass);
            }
            //2、首先确定表各部分及外部container
            this.tContainer = $(this._opt.freezeContainer);
            //3、判断data是否是数组,并准备数据
            if (!_.isArray(this._opt.data)) {
                $.auto.alert("错误", "传入的数据不是数组，请检查！");
                return;
            }
            this.showData = _.isFunction(this._opt.filter) ?
                _.filter(this._opt.data, this._opt.filter) :
                this._opt.data;
            this.rowCount = this.showData.length;
            //3.5 如果是树数据，且提供了treeStartOn，那么要对数据进行排序
            if (_.isFunction(this._opt.treeStartOn)) {
                var sortedData_1 = [];
                var startData_1 = [];
                var remainedData_1 = [];
                _.each(this.showData, function (row) {
                    row["_isMarked"] = false;
                    scope._opt.treeStartOn(row) ? startData_1.push(row) : remainedData_1.push(row);
                });
                _.each(startData_1, function (row) {
                    sortedData_1.push(row);
                    scope.rec_Treerows(row, remainedData_1, sortedData_1);
                });
                this.showData = sortedData_1;
            }
            //4、如果没有给定headerFields,以及header,则要根据第一行数据生成。
            if (this._opt.data.length) {
                if (this._opt.headerFields.length == 0) {
                    for (var key in this._opt.data[0])
                        this._opt.headerFields.push(key);
                }
                if (this._opt.header.length == 0) {
                    var arrHead = [];
                    for (var key in this._opt.data[0])
                        arrHead.push({ title: key, span: [] });
                    this._opt.header.push(arrHead);
                }
            }
            //5、插入序号列
            if (this._opt.isRownumber) {
                if (this._opt.headerFields.indexOf(AutoTable.DefaultRownumID) == -1) {
                    this._opt.headerFields.unshift(AutoTable.DefaultRownumID);
                    this._opt.header2Fields.length && this._opt.header2Fields.unshift(AutoTable.DefaultRownumID);
                }
            }
            scope.columnsCount = scope._opt.headerFields.length;
            //如果没有给出列宽度或给的不够。都要补齐 -1
            if (scope._opt.columnsWidths.length < scope.columnsCount) {
                _.times(scope.columnsCount - scope._opt.columnsWidths.length, function () { scope._opt.columnsWidths.push(-1); });
            }
            //6、获取字段索引信息
            _.each(this._opt.headerFields, function (f, i) { scope.fieldsDict[f] = i; });
            this._opt.header2Fields.length && _.each(this._opt.header2Fields, function (f, i) { scope.fieldsDict[f] = i; });
            //7、判断编辑功能
            if (this._opt.editFields.length > 0 &&
                this._opt.editKeyFields.length > 0 &&
                this._opt.editUrl != '' &&
                this._opt.editTable != '') {
                this.isEditable = true;
                this.me.css('table-layout', 'fixed');
                //编辑提示框
                if (this._opt.editTopHover) {
                    this.tEditTopHover = $("autoEditTopHover");
                    if (!this.tEditTopHover.length) {
                        this.tEditTopHover = $("<div class='autoEditTopHover'>");
                        $('body').append(this.tEditTopHover);
                    }
                }
            }
        };
        AutoTable.prototype.renderColgroup = function () {
            var cols = _.reduce(this._opt.columnsWidths, function (sum, w) {
                return sum + (w > 0 ? "<col style='width:" + w + "px;'/>" : "<col />");
            }, "");
            this.tcolgroup = "<colgroup>" + cols + "</colgroup>";
        };
        //渲染表头。表头以th为基本单元缓存
        AutoTable.prototype.createTh = function (thOpt) {
            if (thOpt._cache)
                return thOpt._cache;
            var th = '', th_attr = '', th_text = '';
            var arr = thOpt.title.split("|");
            //如果有ID
            if (arr[1]) {
                //如果是排序，则标题显示为<a class="autoSort" >title</a> 否则 直接显示
                if (_.includes(this._opt.sortFields, arr[1])) {
                    th_text += "<a class='autoSort' data-field=" + arr[1] + ">" + arr[0] + "</a> ";
                }
                else {
                    th_text += arr[0];
                }
                th_attr += "id=\"" + (this.prefix + arr[1]) + "\" data-field=\"" + arr[1] + "\" ";
            }
            else {
                th_text += arr[0];
            }
            //设置rowspan colspan
            (thOpt.span[0] && thOpt.span[0] != 1) && (th_attr += "colspan=\"" + thOpt.span[0] + "\" ");
            (thOpt.span[1] && thOpt.span[1] != 1) && (th_attr += "rowspan=\"" + thOpt.span[1] + "\" ");
            (thOpt.span[2]) && (th_attr += thOpt.span[2]);
            th = "<th " + th_attr + ">" + th_text + "</th>";
            thOpt._cache = th;
            return th;
        };
        /**flag=1 上表头   2：下表头 */
        AutoTable.prototype.renderThead = function (flag) {
            if (flag === void 0) { flag = 1; }
            var scope = this;
            //当前表头参数
            var headeropt = flag == 1 ? this._opt.header : this._opt.header2;
            //新版本中，每一行是一个数组。但老版本是{}.老版本转换一下
            if (!_.isArray(headeropt[0])) {
                var header_1 = [];
                _.each(headeropt, function (old_row) {
                    var row = [];
                    _.map(old_row, function (v, k) {
                        row.push({ title: k, span: v });
                    });
                    header_1.push(row);
                });
                if (flag == 1) {
                    this._opt.header = header_1;
                }
                else {
                    this._opt.header2 = header_1;
                }
                headeropt = header_1;
            }
            //生成表头内容
            var trs = _.reduce(headeropt, function (trs, row) {
                var ths = _.reduce(row, function (result, thOpt) {
                    return result += scope.createTh(thOpt);
                }, '');
                return trs += (flag == 1 ? "<tr>" + ths + "</tr>" : "<tr class=\"autoheader2\">" + ths + "</tr>");
            }, '');
            if (flag == 1)
                scope.thead = "<thead>" + trs + "</thead>";
            else
                scope.thead2 = trs;
            if (flag == 1 && this._opt.header2Fields.length > 0) {
                scope.renderThead(2);
            }
        };
        //渲染表身，不再缓存行
        AutoTable.prototype.createTR = function (row, rowidx, vMerge, flag) {
            if (flag === void 0) { flag = 1; }
            var scope = this;
            var tr = '', tr_attr = '', tds = '';
            this._opt.tooltipOnRow && (tr_attr += "title=\"" + this._opt.tooltipOnRow(row) + "\" ");
            if (this._opt.keydataOnRow) {
                _.each(this._opt.keydataOnRow, function (key) {
                    tr_attr += "data-" + key + "=\"" + row[key] + "\" ";
                });
            }
            //循环生成td
            var headerfield = flag == 1 ? this._opt.headerFields : this._opt.header2Fields;
            _.each(headerfield, function (field, idx) {
                var td_attr = '', td_text = '', td_class = '';
                td_class += (scope.prefix + field);
                //添加列标识
                td_attr += "data-field=" + field + " ";
                //如果该列需要纵向合并，且该列值不同以上面一个值，则其是一个新单元格.向下搜索长度合并。
                //如果是null，刚不进行合并
                if (_.includes(scope._opt.mergeFields, field)) {
                    if (row[field] != null) {
                        //不等表示是新值，插入td. 否则表示与上一行相同，忽略生成td。
                        if (row[field] == vMerge[field]) {
                            return; //忽略生成td
                        }
                        else {
                            vMerge[field] = row[field];
                            var rowspan = 1;
                            while ((rowidx + rowspan) <= scope.end) {
                                if (scope.showData[rowidx + rowspan][field] == vMerge[field])
                                    rowspan++;
                                else
                                    break;
                            }
                            rowspan > 1 && (td_attr += "rowspan=\"" + rowspan + "\" ");
                        }
                    }
                    else {
                        vMerge[field] = row[field];
                    }
                }
                //求值
                var curColumn = scope._opt.columns[field];
                var value = row[field];
                if (curColumn && _.isFunction(curColumn.formator)) {
                    value = curColumn.formator(value, row);
                }
                else {
                    value = (value == 0 ? scope._opt.zeroShowAs : (value || scope._opt.nullShowAs));
                }
                //冻结
                scope._opt.freezeFields.indexOf(field) >= 0 && (td_class += (" " + AutoTable.DefaultFreezeClassName));
                //列序号 索引。
                td_attr += "data-index=\"" + idx + "\" ";
                //td上的提示
                if (curColumn && _.isFunction(curColumn.tooltip)) {
                    td_attr += "title=\"" + curColumn.tooltip(row[field], row) + "\" ";
                }
                //field是否缩进
                if (scope._opt.treeField == field && _.isFunction(scope._opt.treeIndentOn)) {
                    //此处循环比较隐晦。目的是当上表头时，进行缩进判断。  下表头时，直接用上表头的Indent进行绘制就好了。
                    //原本结构应写为：  if(flag==1)  while(true){ ....}    else { do nothing .}
                    //                  td_text+= .........
                    while (flag == 1) {
                        if (scope.arrIndented.length == 0) {
                            scope.arrIndented.push(rowidx);
                            scope.nIndent = 0;
                            break;
                        }
                        else {
                            var lastIndent = scope.arrIndented.slice(-1)[0];
                            //是子级
                            if (scope._opt.treeIndentOn(scope.showData[lastIndent], scope.showData[rowidx])) {
                                //缩进并保存该行
                                scope.nIndent++;
                                scope.arrIndented.push(rowidx);
                                break; //跳出来
                            }
                            else {
                                scope.arrIndented.pop();
                                scope.nIndent--; //此处不跳，继续向上找上一级
                            }
                        }
                    }
                    scope.nIndent && (td_text += _.repeat('<div class="auto-indent"></div>', scope.nIndent));
                    //默认显示到1级。 但第1级的行肯定要为显示折叠，而0级是打开
                    //如果没有子级，则必须不显示该三角。但没有好办法判断，所以主动访问一下下一行来判断。
                    if (rowidx < scope.end && scope._opt.treeIndentOn(scope.showData[rowidx], scope.showData[rowidx + 1])) {
                        td_text += "<div class=\"auto-indent " + (scope.nIndent <= scope._opt.treeIndentShowLevel - 1 ? "auto-expanded" : "auto-collapsed") + "\"></div>";
                    }
                    else {
                        td_text += '<div class="auto-indent"></div>'; //否则只加一个占位符就好了。
                    }
                    tr_attr += "data-indent=\"" + scope.nIndent + "\" "; //注意，此处是向外层循环中，写入值 。写入到tr的属性上。
                }
                //可编辑
                if (scope.isEditable &&
                    (scope._opt.editOn == null || ((_.isFunction(scope._opt.editOn)) && scope._opt.editOn(field, row))) &&
                    _.includes(scope._opt.editFields, field)) {
                    var kv_1 = {};
                    _.each(scope._opt.editKeyFields, function (f) {
                        kv_1[f] = row[f];
                    });
                    //只绑定值，当前行的主键值。 url，table是全局使用，不用绑定。
                    td_class += (" " + AutoTable.DefaultEditClassName);
                    td_text += ("<input class=\"" + AutoTable.DefaultEditInputClassName + "\" value=\"" + value + "\" data-field=\"" + field + "\" data-kv='" + JSON.stringify(kv_1) + "' data-old=\"" + value + "\" />");
                }
                else {
                    td_text += value;
                }
                tds += "<td class=\"" + td_class + "\"  " + td_attr + ">" + td_text + "</td>";
            });
            tr = "<tr " + tr_attr + ">" + tds + "</tr>";
            return tr;
        };
        AutoTable.prototype.renderTbody = function () {
            var scope = this;
            var trs = '';
            var trs2 = ''; //保存下表身的数据行
            scope.start = 0, scope.end = this.showData.length - 1;
            if (scope.end < 0)
                return;
            //分页时，设置起始行
            if (this._opt.isPageable) {
                scope.start = (this._opt.pageNumber - 1) * this._opt.pageSize;
                scope.end = Math.min(this._opt.pageNumber * this._opt.pageSize - 1, scope.end);
            }
            //在生成body之前，设置一下缩进值
            scope.arrIndented = [];
            /** 用于纵向合并判定,第一次访问undefined*/
            var vMerge1 = {}, vMerge2 = {};
            _.each(this.showData, function (row, ridx) {
                row[AutoTable.DefaultRownumID] = ridx + 1;
                if (ridx >= scope.start && ridx <= scope.end) {
                    trs += scope.createTR(row, ridx, vMerge1, 1);
                    scope._opt.header2Fields.length && (trs2 += scope.createTR(row, ridx, vMerge2, 2));
                }
            });
            scope.tbody = trs;
            scope.tbody2 = trs2;
        };
        AutoTable.prototype.renderTfoot = function () {
            if (!this._opt.isFooter)
                return;
            var scope = this;
            var td_attr = "", td_text = "";
            //临时保存下拉里的option,上页，下页
            var options = '', btn1 = '', btn2 = '';
            td_attr += ("colspan=\"" + this.columnsCount + "\" ");
            if (this._opt.isPageable) {
                //页大小的列表
                this.pageCount = Math.floor((this.rowCount + this._opt.pageSize - 1) / this._opt.pageSize);
                _.each(this._opt.pageSizeList, function (psl) {
                    options += "<option  " + (psl == scope._opt.pageSize ? 'selected="true"' : '') + ">" + psl + "</option>";
                });
                options += '<option value="all">全部</option>';
                td_text += ("\u5171" + this.rowCount + "\u6761&nbsp;<span>\u6BCF\u9875<select class=\"psSelect\">" + options + "</select>\u6761</span>");
                //当前页码跳转
                options = '';
                for (var i = 1; i <= this.pageCount; i++) {
                    options += (i == scope._opt.pageNumber) ? "<option selected=\"true\">" + i + "</option>" : "<option>" + i + "</option>";
                }
                td_text += ("<span>\u8DF3\u8F6C<select class=\"pnSelect\">" + options + "</select>\u9875</span>");
                //上页，下页
                btn1 = "<button type=\"button\" class=\"btn btn-default btn-xs\" data-flag=\"prepage\" " + (this._opt.pageNumber == 1 ? "disabled" : "") + ">\u4E0A\u4E00\u9875</button>";
                btn2 = "<button type=\"button\" class=\"btn btn-default btn-xs\" data-flag=\"nextpage\" " + (this._opt.pageNumber >= this.pageCount ? "disabled" : "") + ">\u4E0B\u4E00\u9875</button>";
                td_text += ("<div class=\"btn-group autoPager\">" + btn1 + btn2 + "</div>");
            }
            else {
                td_text += '<button type="button" class="btn btn-default btn-xs" data-flag="paging">启用分页</button>';
            }
            if (this._opt.isSaveable) {
                td_text += "<button type=\"button\"  class=\"btn btn-default btn-xs " + AutoTable.DefaultSaveButtonClassName + "\" >\u5BFC\u51FA</button>";
            }
            this.tfoot = "<td " + td_attr + ">" + td_text + "</td>";
        };
        AutoTable.prototype.findDoms = function () {
            //这里要重新绑定
            if (this.isEditable) {
                //仅用于键盘跳转时，能更快速。要是跳转不用，可以去掉
                this.allEditInput = this.me.find("." + AutoTable.DefaultEditInputClassName);
            }
            if (this._opt.isScrollable) {
                this.frzHead = this.me.find("thead th");
                this.frzTd = this.me.find("." + AutoTable.DefaultFreezeClassName);
            }
            //每次重新生成表身时，都要按照默认的显示缩进的级别进行显示。
            this._opt.treeField != "" && this.hideTreeCollapse();
        };
        AutoTable.prototype.readHeadIndex = function () {
            //第一次加载表头后，更新一下每个th所属的index
            var scope = this;
            //计算每一列对应哪些表头中的th
            var pos = [[], [], [], [], [], [], [], [], [], []]; //默认表头最大为10行。
            var x = 0, y = 0; //pos是二维数组，表示表头的分布着哪些th
            var thInCol = []; //每一列所包含的th
            var tmp1, tmp2;
            var allTheadrows = this.me.find("thead>tr");
            if (this._opt.header2Fields.length > 0) {
                allTheadrows = allTheadrows.add(this.me.find(".autoheader2"));
            }
            allTheadrows.each(function (iTR, tr) {
                $(tr).find('th').each(function (iTH, th) {
                    var c = th.colSpan, r = th.rowSpan;
                    for (tmp1 = 0; tmp1 < c; tmp1++) {
                        for (tmp2 = 0; tmp2 < r; tmp2++) {
                            //如果当前pos已有值，则向后移一格
                            while (typeof pos[y + tmp2][x + tmp1] !== 'undefined') {
                                x++;
                            }
                            pos[y + tmp2][x + tmp1] = th;
                        }
                        thInCol[x + tmp1] = thInCol[x + tmp1] || [];
                        thInCol[x + tmp1].push(th);
                    }
                    //处理下一个td之前，先修改x的值
                    x = x + th.colSpan;
                });
                ////处理下一个tr之前，先修改y的值
                x = 0;
                y++;
            });
            scope.fieldsDict = {}; //每个字段对应的列号,及表头列。  
            //上表头中出现的列了。
            $.each(this._opt.headerFields, function (i, field) {
                scope.fieldsDict[field] = {
                    index: i,
                    ths: thInCol[i]
                };
            });
            //下表头中出现的列了。下表列与上表列相重的部分，务必在同一列上。比如ny,dwmc这些，上下表头要一致！
            $.each(this._opt.header2Fields, function (i, field) {
                scope.fieldsDict[field] = {
                    index: i,
                    ths: thInCol[i]
                };
            });
        };
        /**
         * 绑定点击变色，页面大小，页数变化，排序，锁定表头及列
         */
        AutoTable.prototype.bindEvents = function () {
            var scope = this;
            //单击变色,单击输入框则不变色
            if (this._opt.selectMode != SelectMode.NONE) {
                this.me.on('click' + AutoTable.DefaultEventNamespace, 'tbody>tr', function (e) {
                    var $target = $(e.target);
                    if (!$target.is('input')) {
                        var $tr = $(this);
                        //单选时,如果点击是不是已经选择行，则要清除选择
                        if ((scope._opt.selectMode == SelectMode.SINGLE) && (!$tr.hasClass(AutoTable.DefaultSelectedClassName))) {
                            scope.me.find("." + AutoTable.DefaultSelectedClassName).removeClass(AutoTable.DefaultSelectedClassName);
                        }
                        var rowspan = parseInt($target.attr("rowspan") || '1'); //若td 无rowspan,则取到undefined,转数字后为NaN
                        while (rowspan >= 1) {
                            $tr.toggleClass(AutoTable.DefaultSelectedClassName);
                            $tr = $tr.next();
                            rowspan--;
                        }
                        scope.me.trigger("autoselected");
                    }
                });
            }
            //页面大小变化,页数变化
            this.me.on('change' + AutoTable.DefaultEventNamespace, 'tfoot select', function (e) {
                var $sel = $(this);
                //修改全局的参数
                if ($sel.hasClass("psSelect")) {
                    if ($sel.val() == "all") {
                        scope._opt.isPageable = false;
                    }
                    else {
                        scope._opt.pageSize = parseInt($sel.val());
                        scope._opt.pageNumber = 1;
                    }
                }
                else if ($sel.hasClass("pnSelect")) {
                    scope._opt.pageNumber = parseInt($sel.val());
                }
                scope.reloadTbodyTfoot();
            });
            //上一页，下一页
            this.me.on('click' + AutoTable.DefaultEventNamespace, 'tfoot button', function (e) {
                var $sel = $(this);
                if ($sel.data("flag") == "prepage") {
                    scope._opt.pageNumber--;
                }
                else if ($sel.data("flag") == "nextpage") {
                    scope._opt.pageNumber++;
                }
                else if ($sel.data("flag") == "paging") {
                    scope._opt.pageNumber = 1;
                    scope._opt.isPageable = true;
                }
                scope.reloadTbodyTfoot();
            });
            //排序
            this.me.on('click' + AutoTable.DefaultEventNamespace, 'thead .autoSort,.autoheader2 .autoSort', function (e) {
                var field = $(this).data("field");
                //方向，true正序  false为倒序
                var direction = scope.sortInfo[field];
                direction = _.isUndefined(direction) ? true : (!direction);
                //保存起来
                scope.sortInfo[field] = direction;
                scope.showData = _.orderBy(scope.showData, [field], direction ? ["asc"] : ["desc"]);
                scope._opt.pageNumber = 1;
                scope.reloadTbodyTfoot();
            });
            //锁定
            if (scope._opt.isScrollable) {
                scope.tContainer.on("scroll" + AutoTable.DefaultEventNamespace, function () {
                    var top = scope.tContainer.scrollTop();
                    var left = scope.tContainer.scrollLeft();
                    scope.frzHead.css({ "transform": "translate(0," + top + "px)" });
                    scope.frzTd.css({ "transform": "translate(" + left + "px,0)" });
                });
            }
            //隐藏及显示事件
            this.me.on('hide' + AutoTable.DefaultEventNamespace, function (e, fields) {
                if (typeof fields == 'undefined')
                    return; ///表格中带datetimepicker时，也向上冒泡产生show 事件，屏蔽之。
                //传入逗号分隔的字符串，或一个数据。每一项是需要隐藏的列。
                var fArr = fields.split(',');
                _.each(fArr, function (f) {
                    if (((_.includes(scope._opt.headerFields, f)) || _.includes(scope._opt.header2Fields, f)) &&
                        (!_.includes(scope.hidedFields, f)) //&& 且未隐藏过
                    ) {
                        scope.hidedFields.push(f);
                        var idx = scope.fieldsDict[f].index;
                        var col = scope.me.find("col").eq(idx);
                        var w = col.width();
                        col.data("w", col.width()).addClass('auto-hide-col');
                        _.each(scope.fieldsDict[f].ths, function (th) {
                            var $th = $(th);
                            var hidCount = $th.data('hidCount') || 0;
                            $th.data('hidCount', ++hidCount);
                            hidCount == $th.prop('colspan') && $th.addClass('auto-hide-headtext');
                        });
                        w > 0 && scope.me.width('-=' + w);
                    }
                });
            });
            //隐藏及显示事件
            this.me.on('show' + AutoTable.DefaultEventNamespace, function (e, fields) {
                if (typeof fields == 'undefined')
                    return; ///表格中带datetimepicker时，也向上冒泡产生show 事件，屏蔽之。
                //传入逗号分隔的字符串，或一个数据。每一项是需要隐藏的列。
                var fArr = fields.split(',');
                _.each(fArr, function (f) {
                    if (_.includes(scope.hidedFields, f)) {
                        _.remove(scope.hidedFields, function (v) { return v == f; });
                        var idx = scope.fieldsDict[f].index;
                        var col = scope.me.find("col").eq(idx);
                        var w = col.data('w');
                        w > 0 && scope.me.width('+=' + w);
                        col.removeClass('auto-hide-col');
                        _.each(scope.fieldsDict[f].ths, function (th) {
                            var $th = $(th);
                            var hidCount = $th.data('hidCount');
                            $th.data('hidCount', --hidCount);
                            $th.removeClass('auto-hide-headtext');
                        });
                        w > 0 && console.log('show', w);
                    }
                });
            });
            //导出
            if (this._opt.isSaveable) {
                this.me.on('export' + AutoTable.DefaultEventNamespace, this.ExportData.bind(this));
                this.me.on('click' + AutoTable.DefaultEventNamespace, '.' + AutoTable.DefaultSaveButtonClassName, this.ExportData.bind(this));
            }
            //树级结构时，点击三角箭头时，要折叠或显示    .auto-expanded  .auto-collapsed
            //切换当前箭头，之后该行向下找到另一个同级的行截止。这之间的所有的下一级缩进全显示，
            //待展开
            if (this._opt.treeField) {
                this.me.on("click" + AutoTable.DefaultEventNamespace, ".auto-collapsed", function () {
                    var $curTri = $(this);
                    var $tr = $curTri.parents("tr");
                    var curIndent = $tr.data("indent");
                    //切换当前箭头
                    $curTri.removeClass("auto-collapsed").addClass("auto-expanded");
                    //此处暂时不考虑下表头的问题。  考虑时，要考虑点击是哪个。要折叠或展开，上下表头要同步操作的。想想也复杂
                    $tr.nextAll("tr").each(function (i, tr) {
                        var $tmpTr = $(tr);
                        var tmpIndent = $tmpTr.data("indent");
                        //如果遇到下表头，则跳出。
                        if ($tmpTr.hasClass("autoheader2"))
                            return false;
                        //如果同级上级，则跳出
                        if (tmpIndent <= curIndent)
                            return false;
                        //如果自己的上级是展开的，那么自己就显示 .倒序找上级。
                        var $preTrs = $tmpTr.prevAll("tr");
                        for (var i = $preTrs.length - 1; i >= 0; i--) {
                            var $pTr = $($preTrs.get(i));
                            if ($pTr.hasClass("autoheader2"))
                                break;
                            if ($pTr.data("indent") == tmpIndent - 1) {
                                //如果上级展开，自己显示  此处还有bug
                                if ($pTr.find(".auto-expanded").length > 0) {
                                    $tmpTr.show();
                                    break;
                                }
                            }
                        }
                    });
                });
                //待折叠
                this.me.on("click" + AutoTable.DefaultEventNamespace, ".auto-expanded", function () {
                    var $curTri = $(this);
                    var $tr = $curTri.parents("tr");
                    var curIndent = $tr.data("indent");
                    //切换当前箭头
                    $curTri.removeClass("auto-expanded").addClass("auto-collapsed");
                    //此处暂时不考虑下表头的问题。  考虑时，要考虑点击是哪个。要折叠或展开，上下表头要同步操作的。想想也复杂
                    $tr.nextAll("[data-indent]").each(function (i, tr) {
                        var $tmpTr = $(tr);
                        var tmpIndent = $tmpTr.data("indent");
                        //如果同级或上级，则跳出
                        if (tmpIndent <= curIndent)
                            return false;
                        //下表头，则跳出
                        if ($tmpTr.hasClass("autoheader2"))
                            return false;
                        $tmpTr.hide();
                    });
                });
            }
            if (this.isEditable) {
                var scope_1 = this;
                //提交修改
                scope_1.me.on("focusout" + AutoTable.DefaultEventNamespace, '.autoEditinput', function (e) {
                    //如果有hover框，则隐藏它
                    scope_1._opt.editTopHover && scope_1.tEditTopHover.hide();
                    //以下提交数据
                    var $input = $(this);
                    var field = $input.data("field"), kv = $input.data("kv"), old = $input.data("old"), v = $.trim($input.val());
                    if (v == old)
                        return;
                    var upKv = _.clone(kv);
                    //附加上这些值一起上传到后台。这样后台可以用更通用的方法来处理所有的请求。
                    upKv[field] = v;
                    upKv['old_' + field] = old;
                    upKv["_TABLE"] = scope_1._opt.editTable;
                    upKv["_FIELD"] = field;
                    //如果有验证，则先验证再提交。
                    //同时引发三个事件，附带上传元素，正修改的单元格及成功标志
                    if (_.isNull(scope_1._opt.editBeforeUpload) || (_.isFunction(scope_1._opt.editBeforeUpload) && scope_1._opt.editBeforeUpload(upKv, field))) {
                        scope_1.me.trigger('beforeCellEdited', [upKv, $input]);
                        $.ajax(scope_1._opt.editUrl, {
                            cache: false, type: 'POST',
                            data: upKv, dataType: 'json'
                        }).done(function (ret) {
                            $input.data('old', v);
                            //从showdata中找到当前行，把该field的值修改掉
                            _.find(scope_1.showData, function (row) {
                                if (_.isMatch(row, kv)) {
                                    row[field] = v;
                                    return true;
                                }
                                return false;
                            });
                            $input.addClass(AutoTable.DefaultCellEdited);
                            scope_1.me.trigger('cellEdited', [upKv, $input]);
                            scope_1.me.trigger('afterCellEdited', [upKv, $input, true]);
                        }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
                            $input.val(old);
                            scope_1.me.trigger('afterCellEdited', [upKv, $input, false]);
                        });
                    }
                });
                //键盘操作
                this.me.on('keydown' + AutoTable.DefaultEventNamespace, '.' + AutoTable.DefaultEditInputClassName, function (event) {
                    var newinput = null;
                    if (event.keyCode == 13 || event.keyCode == 39) {
                        var idx = scope_1.allEditInput.index(this);
                        if (idx < scope_1.allEditInput.length - 1)
                            newinput = $(scope_1.allEditInput[idx + 1]);
                    }
                    if (event.keyCode == 37) {
                        var idx = scope_1.allEditInput.index(this);
                        if (idx > 0)
                            newinput = $(scope_1.allEditInput[idx - 1]);
                    }
                    if (event.keyCode == 38) {
                        var field = $(this).data('field');
                        var list = scope_1.allEditInput.filter("[data-field='" + field + "']");
                        var idx = list.index(this);
                        if (idx > 0)
                            newinput = $(list[idx - 1]);
                    }
                    if (event.keyCode == 40) {
                        var field = $(this).data('field');
                        var list = scope_1.allEditInput.filter("[data-field='" + field + "']");
                        var idx = list.index(this);
                        if (idx < list.length - 1)
                            newinput = $(list[idx + 1]);
                    }
                    if (newinput) {
                        newinput.selectWord();
                        if (!_.isUndefined(newinput[0].scrollIntoView)) {
                            newinput[0].scrollIntoView();
                        }
                        return false;
                    }
                    return true;
                }).on("paste" + AutoTable.DefaultEventNamespace, "." + AutoTable.DefaultEditClassName, function (event) {
                    event.stopPropagation();
                    event.preventDefault();
                    var origEvent = event.originalEvent;
                    var cd = origEvent.clipboardData || window.clipboardData;
                    if (!cd)
                        return; //firefox会走这吗？
                    var content = cd.getData("text");
                    var rows = content.indexOf('\r\n') == -1 ? content.split('\n') : content.split('\r\n');
                    //如果从excel粘贴，则需要弹出最后一个空元素。如果是纯文本，则最后一个非空，不需要弹出。
                    if ($.trim(rows.slice(-1)[0]) == '') {
                        rows.pop();
                    }
                    var xpos = $(this);
                    var ypos = $(this);
                    var field = xpos.data('field');
                    $.each(rows, function (i, r) {
                        xpos = ypos;
                        var cols = r.split('\t');
                        $.each(cols, function (j, c) {
                            xpos.val($.trim(c)).focus().blur();
                            var idx = scope_1.allEditInput.index(xpos);
                            if (idx < scope_1.allEditInput.length - 1) {
                                xpos = $(scope_1.allEditInput[idx + 1]);
                            }
                            else {
                                return;
                            } //向后无元素了
                        });
                        var list = scope_1.allEditInput.filter("[data-field='" + field + "']");
                        var index = list.index(ypos);
                        if (index < list.length - 1)
                            ypos = $(list[index + 1]);
                        else
                            return; //向下无元素了
                    });
                });
                //编辑需要显示hover部分时,每次输入都要重新显示内容。
                if (scope_1._opt.editTopHover) {
                    this.me.on("input" + AutoTable.DefaultEventNamespace, '.autoEditinput', function () {
                        var result = $(this).val();
                        scope_1.tEditTopHover.text(scope_1.fmtNum(result));
                    });
                    this.me.on("focusin" + AutoTable.DefaultEventNamespace, '.autoEditinput', function () {
                        var $ipt = $(this);
                        var offset = $ipt.offset();
                        var result = $ipt.val();
                        setTimeout(function () {
                            scope_1.tEditTopHover.css({ top: offset.top - 35, left: offset.left })
                                .css("min-width", $ipt.outerWidth())
                                .text(scope_1.fmtNum(result)).show();
                        }, 200);
                    });
                }
            }
            //每次load reloaded都要重定位滚动
            this.me.on("loaded" + AutoTable.DefaultEventNamespace + " reloaded" + AutoTable.DefaultEventNamespace, function () {
                if (scope._opt.isScrollable)
                    scope.tContainer.trigger("scroll");
            });
        };
        //格式化数字，整数部分大于4位，则用千分位表示，小数部分每两位加个空格
        AutoTable.prototype.fmtNum = function (inNum) {
            var fst = "", snd = "";
            var arr;
            var num = inNum.toString().replace(/\s+/g, '');
            if (!/^[-]?[0-9]+(.[0-9]*)?$/.test(num))
                return inNum;
            var _a = num.split("."), a = _a[0], b = _a[1];
            //处理整数
            a[0] == '-' && (fst = '-') && (a = a.slice(1));
            if (a.length > 4) {
                var len = a.length % 3 ? a.length % 3 : 3;
                fst += (a.slice(0, len));
                a = a.slice(len);
                while (a.length) {
                    fst += ("," + a.slice(0, 3));
                    a = a.slice(3);
                }
            }
            else {
                fst += a;
            }
            //处理小数
            if (b && b.length > 1) {
                snd = '.';
                while (b.length) {
                    snd += (b.slice(0, 2) + " ");
                    b = b.slice(2);
                }
            }
            return fst + snd;
        };
        /**导出报表结果*/
        AutoTable.prototype.ExportData = function () {
            var scope = this;
            var cloneOpt = $.extend(true, {}, this._opt);
            var showData = JSON.parse(JSON.stringify(this.showData));
            //表头里的标签，比如换行和上标，要在后台进行处理
            var uData = _.pick(cloneOpt, "header", "header2", "headerFields", "header2Fields", "freezeFields");
            var allfield = _.uniq(cloneOpt.header2Fields.concat(cloneOpt.headerFields));
            var rownum = 1;
            //移除表头里的_catch
            _.each(uData.header, function (row) {
                _.each(row, function (th) {
                    delete th._cache;
                });
            });
            _.each(uData.header2, function (row) {
                _.each(row, function (th) {
                    delete th._cache;
                });
            });
            //重新考虑excel的因素，把tbody的内容重新格式化一次
            _.each(showData, function (row) {
                _.each(allfield, function (key) {
                    if (key == "rownum")
                        row[key] = rownum++;
                    else {
                        //显示值的输出。根据columns.formator来格式化数据到uData里
                        if (scope._opt.columns[key] && _.isFunction(scope._opt.columns[key].formator)) {
                            row[key] = scope._opt.columns[key].formator(row[key], row);
                            if (row[key] == null) {
                                row[key] = "";
                            }
                            else {
                                //数据部分要替换掉html标签
                                row[key] = row[key].replace(/<[^>]+>/g, "");
                            }
                        }
                        else
                            row[key] = (row[key] === 0 ? scope._opt.zeroShowAs : (row[key] || scope._opt.nullShowAs)); //值为0，显示为0. null，不显示。
                    }
                });
            });
            uData.showData = showData;
            //构造一个下载窗体.
            var $iframe = $('<iframe />');
            var $form = $('<form target="down-file-iframe" method="post" />');
            $form.attr('action', this._opt.saveURL);
            var size = 84555;
            var content = JSON.stringify(uData);
            var d = 0;
            //上传的name 是 d1,d2。。。。
            while (content.length > 0) {
                d++;
                $form.append("<input  name='d" + d + "' value='" + content.slice(0, size) + "' />");
                content = content.slice(size);
            }
            $form.append("<input  name='cnt' value='" + d + "' />");
            $iframe.append($form);
            $(document.body).append($iframe);
            $form[0].submit();
            $iframe.remove();
        };
        /**有树时，要隐藏一下相关的行*/
        AutoTable.prototype.hideTreeCollapse = function () {
            var scope = this;
            if (this._opt.treeField != "") {
                scope.me.find("tr[data-indent]").each(function (i, tr) {
                    var $tr = $(tr);
                    $tr.toggle($tr.data("indent") <= scope._opt.treeIndentShowLevel);
                });
            }
        };
        AutoTable.DefaultClassName = "autotable";
        AutoTable.DefaultEditClassName = "autoEdit";
        AutoTable.DefaultEditInputClassName = "autoEditinput";
        AutoTable.DefaultFreezeClassName = "frzTD";
        AutoTable.DefaultEventNamespace = ".autoTableEvent";
        AutoTable.DefaultSelectedClassName = "autoselected";
        AutoTable.DefaultSaveButtonClassName = "autoSave";
        AutoTable.DefaultCellEdited = 'cellEdited';
        AutoTable.DefaultRownumID = "_rownum";
        return AutoTable;
    }());
    AUTO.AutoTable = AutoTable;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
/*使用说明
该功能自动把form标签内，填充上各个表单元素。表单元素在fields中，要一一指定。
在处理tree的下拉时，需要ztree的支持。
当传入values时，通常表示是要编辑数据。它是一个数组，但只用它第一行值。
*/
var AUTO;
(function (AUTO) {
    /**依赖日期 控件、zTree   目前假设ID是主键*/
    var AutoForm = (function () {
        function AutoForm(element, option) {
            /**主键记录*/
            this.keysList = [];
            this.renderFuncMapper = {
                "string": this.renderString,
                "number": this.renderNumber,
                "select": this.renderSelect,
                "tree": this.renderTree,
                "date": this.renderDate,
                "month": this.renderMonth,
                "year": this.renderYear,
                "file": this.renderFile,
                "textarea": this.renderTextarea,
                "password": this.renderPassword
            };
            this._opt = {
                action: "",
                ajaxurl: "",
                cols: 2,
                fields: [],
                tableName: "",
                values: []
            };
            /** 等待个数。因为有些是异步插入的，要等这些异步完成才行 */
            this.waitCount = 0;
            this._opt = $.extend(this._opt, option);
            this.$form = $(element);
            this.init();
            this.renderTable();
            if (this._opt.values.length) {
                this.writeValues();
            }
            this.bindClickEvent();
            this.$form.data("autoform", this);
        }
        AutoForm.prototype.init = function () {
            this.$form.empty()
                .prop("action", this._opt.action)
                .addClass("autoForm")
                .append("<table class='autoFormTable'></table>\n                        <br>\n        <div class=\"autoFormDiv\">\n            <button type=\"button\" class=\"btn btn-warning btnCancel\">\n                <span class=\"glyphicon glyphicon-remove\"></span> \u53D6&nbsp;&nbsp;\u6D88\n            </button>\n            <button type=\"submit\" class=\"btn btn-info btnSave\">\n                <span class=\"glyphicon glyphicon-ok\"></span> \u4FDD&nbsp;&nbsp;\u5B58\n            </button>\n        </div>");
            this.$table = this.$form.find(".autoFormTable");
            this.$btnSave = this.$form.find(".btnSave");
            this.$btnCancle = this.$form.find(".btnCancel");
        };
        /**根据字段，输出到form的table标签中去,之后绑定日期的功能 .
         * 如果类型是prikey,则添加到form，而不是添加到table中支 */
        AutoForm.prototype.renderTable = function () {
            var scope = this;
            var content = "<tbody><tr>"; //输出到tbody中的内容
            var pos = 0; //用来判断当前位置是否能容下一个字段
            _.each(this._opt.fields, function (item, idx) {
                if (item.type == "prikey") {
                    scope.appendPrikey(item);
                    return;
                }
                if ((pos + item.span) > scope._opt.cols) {
                    content += "</tr><tr>";
                    pos = item.span;
                }
                else {
                    pos += item.span;
                }
                var sndSpan = (item.span > 1) ? item.span * 2 - 1 : 1;
                content += "<td class=\"greyTD\">" + item.title + "</td>";
                content += "<td colspan=\"" + sndSpan + "\">";
                content += scope.renderFuncMapper[item.type].call(scope, item);
                content += "</td>";
            });
            content += "</tr><tbody>";
            this.$table.append(content);
            //绑定日期 的方法
            this.$table.find('[data-type="date"]').autoDate("nyr");
            this.$table.find('[data-type="month"]').autoDate("ny");
            this.$table.find('[data-type="year"]').autoDate("n");
        };
        /**绑定一下取消和保存的事件*/
        AutoForm.prototype.bindClickEvent = function () {
            var scope = this;
            this.$btnCancle.click(function () {
                //直接是触发用户事件
                scope._opt.canceled && scope._opt.canceled();
            });
            this.$btnSave.click(function () {
                scope.saveData();
                return false;
            });
        };
        AutoForm.prototype.appendPrikey = function (item) {
            this.$form.append(" <input name=\"" + item.field + "\" type=\"hidden\" value=\"\">");
            this.keysList.push(item.field);
        };
        AutoForm.prototype.getPlaceholder = function (item) {
            return item.placeholder ? "placeholder=\"" + item.placeholder + "\"" : "";
        };
        AutoForm.prototype.renderString = function (item) {
            return "<input type=\"text\" data-type=\"string\" name=\"" + item.field + "\"  " + this.getPlaceholder(item) + "/>";
        };
        AutoForm.prototype.renderNumber = function (item) {
            return "<input type=\"number\" data-type=\"number\" name=\"" + item.field + "\" step='" + item.step + "'  " + this.getPlaceholder(item) + "/>";
        };
        AutoForm.prototype.renderOptions = function (list) {
            var content = "";
            content += '<option value="">请选择</option>';
            _.each(list, function (item) {
                content += "<option value=\"" + item["ID"] + "\">" + item["MC"] + "</option>;";
            });
            return content;
        };
        /**输出下拉选择， 有异步事件 */
        AutoForm.prototype.renderSelect = function (item) {
            var scope = this;
            var content = "<select data-type=\"select\" name=\"" + item.field + "\" >";
            if (_.isString(item.addData)) {
                //插入一个等待
                scope.waitCount++;
                $.ajax(item.addData, { type: 'GET', data: {}, dataType: 'json' })
                    .done(function (data) {
                    //异步写入下拉菜单
                    scope.$form.find("[name=" + item.field + "]").append(scope.renderOptions(data));
                    scope.waitCount--;
                });
            }
            else if (_.isArray(item.addData)) {
                content += scope.renderOptions(item.addData);
            }
            content += '</select>';
            return content;
        };
        /**输出下拉树， 有异步事件 */
        AutoForm.prototype.renderTree = function (item) {
            var scope = this;
            //隐藏标签用于提交value
            var content = "<input type=\"hidden\" data-type=\"tree\" name=\"" + item.field + "\" />";
            //显示值对应的名称。它没有name属性性，所以不提交
            content += "<input type=\"text\" class='formtreeInput' data-type=\"tree\" data-label=\"" + item.field + "\"  " + this.getPlaceholder(item) + "/>";
            //插入一个等待
            scope.waitCount++;
            content += ("<div class=\"formtree ztree\"></div>");
            //请求树数据,同时
            $.ajax(item.addData, { type: 'GET', data: {}, dataType: 'json' })
                .done(function (treedata) {
                /* _.each(treedata, function(node) {
                         if(node.ISLEAF == "1") {
                             node.icon = "scripts/pluginjs/zTree3.5.21/css/zTreeStyle/img/diy/10.png";
                         } else {
                             node.iconOpen = "scripts/pluginjs/zTree3.5.21/css/zTreeStyle/img/diy/1_open.png";
                             node.iconClose = "scripts/pluginjs/zTree3.5.21/css/zTreeStyle/img/diy/1_close.png";
                         }
                     });
                 */
                var $input = scope.$form.find("[name=" + item.field + "]")
                    .data("treedata", treedata);
                var $text = $input.next();
                var $tree = $text.next();
                //生成树
                var setting = {
                    data: {
                        key: { name: "NAME" },
                        simpleData: { enable: true, idKey: "ID", pIdKey: "PID" }
                    },
                    callback: {
                        onDblClick: function (event, treeId, treeNode) {
                            if (treeNode && treeNode.ISLEAF == '1') {
                                $input.val(treeNode.ID);
                                $text.val(treeNode.NAME);
                            }
                        }
                    }
                };
                //生成树，并打开第一级目录
                var treeObj = $.fn.zTree.init($tree, setting, treedata);
                var nodes = treeObj.getNodes();
                treeObj.expandNode(nodes[0], true, false, true);
                $input.parent().addClass("formtreeTd");
                scope.waitCount--;
            });
            return content;
        };
        AutoForm.prototype.renderDate = function (item) {
            //日期列要增加_RQ的后缀，在后台处理过程中，会将其去掉。
            return "<input type=\"text\" data-type=\"date\" name=\"" + item.field + "_RQ\" " + this.getPlaceholder(item) + "/>";
        };
        AutoForm.prototype.renderMonth = function (item) {
            return "<input type=\"text\" data-type=\"month\" name=\"" + item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        AutoForm.prototype.renderYear = function (item) {
            return "<input type=\"text\" data-type=\"year\" name=\"" + item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        AutoForm.prototype.renderFile = function (item) {
            return "<input type=\"file\" data-type=\"file\" id=\"uploadfile\" name=\"" +
                item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        ;
        AutoForm.prototype.renderTextarea = function (item) {
            return "<textarea style='width:100%;height:80px' rows='3' data-type=\"string\" name=\"" +
                item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        ;
        AutoForm.prototype.renderPassword = function (item) {
            return "<input type=\"password\" data-type=\"string\" name=\"" + item.field + "\" " + this.getPlaceholder(item) + "/>";
        };
        ;
        /** 如果传入了formValues ,那么要将它写到表单中 */
        AutoForm.prototype.writeValues = function () {
            var scope = this;
            //sql返回的对象一般是一个元素的数组，所以直接取0个元素
            if (!scope._opt.values)
                return;
            var row = scope._opt.values[0];
            if (this.waitCount > 0) {
                setTimeout(function () {
                    scope.writeValues();
                }, 500);
            }
            else {
                _.each(this._opt.fields, function (item, idx) {
                    //特殊考虑  日期\树\文件 类型
                    var $input = scope.$form.find("[name=" + item.field + (item.type == "date" ? "_RQ" : "") + "]");
                    var value = row[item.field];
                    if (value) {
                        if (item.type == "date") {
                            value = row[item.field].substr(0, 10);
                        }
                        else if (item.type == "tree") {
                            var $text = $input.next();
                            var $tree = $text.next();
                            var treedata = $input.data("treedata");
                            var treenode = _.find(treedata, function (node) {
                                return node["ID"] == value;
                            });
                            $input.val(treenode.ID);
                            $text.val(treenode.NAME);
                        }
                        else if (item.type != "file") {
                            $input.val(value);
                        }
                    }
                });
            }
        };
        /**首先走beforeSave ,
         *     返回false,则保留页面，让用户修改，
         *     否则
         *         如果是form提交，页面就切换了。
                   如果ajax提交，提交后执行用户saved方法*/
        AutoForm.prototype.saveData = function () {
            var scope = this;
            var updata = this.$form.serializeArray();
            updata.push({ name: "_keys", value: this.keysList.join(",") });
            updata.push({ name: "_table", value: this._opt.tableName });
            //如果beforeSave返回false,则终止上传操作。
            if (_.isFunction(scope._opt.beforeSave) && !scope._opt.beforeSave(updata)) {
                return false;
            }
            if (this._opt.action == "") {
                $.ajax(this._opt.ajaxurl, { type: 'POST', data: updata, dataType: 'json' })
                    .done(function (msg) {
                    //触发用户的事件
                    scope._opt.saved && scope._opt.saved(msg);
                });
            }
            else {
                this.$form[0].submit();
            }
            return true;
        };
        return AutoForm;
    }());
    AUTO.AutoForm = AutoForm;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
var AUTO;
(function (AUTO) {
    var TabPanel = (function () {
        function TabPanel(element, cmd, tabInfo) {
            this._cmd = {
                add: this.AddTab,
                remove: this.RemoveTab,
                removeall: this.RemoveallTab
            };
            this.$el = $(element);
            if (_.isUndefined(cmd)) {
                this.init();
                this.bindEvent();
            }
            else {
                var me = this.$el.data("OriginData");
                me._cmd[cmd].call(me, tabInfo);
            }
        }
        TabPanel.prototype.init = function () {
            this.idList = [];
            this.seqList = [];
            this.$el.addClass(TabPanel.DefaultClassName)
                .html(TabPanel.OutDom + TabPanel.TabMenu);
            /**获取UL标签及菜单,内容 */
            this.tabUL = this.$el.find("ul.tab-tabs");
            this.tabMenu = this.$el.find("div.tab-menus");
            this.tabContent = this.$el.find("div.tab-content");
            this.$el.data("OriginData", this);
        };
        //绑定事件
        TabPanel.prototype.bindEvent = function () {
            var scope = this;
            this.$el.off(TabPanel.DefaultEventName);
            $(window).off(TabPanel.DefaultEventName);
            this.$el.on("click" + TabPanel.DefaultEventName, ".close", function () {
                scope.RemoveTab({ id: $(this).parent().data("id") });
            });
            //默认元素要填充最下方
            $(window).on("resize" + TabPanel.DefaultEventName, function (event) {
                scope.$el.height($(window).height() - scope.$el.offset().top);
            }).trigger("resize");
            //激活时，插入到激活列表中
            this.$el.on('show.bs.tab', 'a[data-toggle="tab"]', function (e) {
                scope.seqList.push($(this).data("id"));
            });
            //在标签页上点右键，弹出菜单
            this.$el.on("contextmenu" + TabPanel.DefaultEventName, ".tab-tabs li", function (event) {
                var $li = $(this);
                var offset = $li.position();
                scope.tabMenu.css({
                    "left": event.offsetX + offset.left,
                    "top": scope.tabUL.height()
                }).find(".dropdown-menu").show();
                //获取到当前标签的id,绑定到tabMenu上去。
                scope.tabMenu.data("select_id", $li.find("a").data("id"));
                return false;
            });
            /*点击关闭按钮时*/
            this.$el.on("click" + TabPanel.DefaultEventName, ".tab-menus a[data-close]", function (event) {
                var flag = $(this).data("close");
                var id = scope.tabMenu.data("select_id").toString(); //强制转成字符，因为idList中存放的字符。
                //索引
                var idx = scope.idList.indexOf(id);
                if (idx > -1) {
                    switch (flag) {
                        case "me":
                            scope.RemoveTab({ id: id }); //ts的缩写方式
                            break;
                        case "right":
                            var toRemove = scope.idList.slice(idx + 1);
                            _.each(toRemove, function (rId) {
                                scope.RemoveTab({ id: rId });
                            });
                            break;
                        case "left":
                            var toRemove = scope.idList.slice(0, idx);
                            _.each(toRemove, function (rId) {
                                scope.RemoveTab({ id: rId });
                            });
                            break;
                        case "other":
                            var toRemove = scope.idList.concat([]);
                            _.each(toRemove, function (rId) {
                                rId != id && scope.RemoveTab({ id: rId });
                            });
                            break;
                        case "all":
                            scope.RemoveallTab();
                            break;
                    }
                }
                //隐藏菜单
                scope.tabMenu.find(".dropdown-menu").hide();
            });
            /**点击标签栏其它地方，关闭菜单*/
            this.$el.on("click" + TabPanel.DefaultEventName, ".tab-tabs", function (event) {
                scope.tabMenu.find(".dropdown-menu").hide();
            });
        };
        /**添加新标签页 */
        TabPanel.prototype.AddTab = function (tabInfo) {
            var idx = this.idList.indexOf(tabInfo.id);
            if (idx >= 0) {
                this.tabUL.find("li>a").eq(idx).tab("show");
                return;
            }
            this.tabUL.append(TabPanel.TabLi(tabInfo));
            this.tabContent.append(TabPanel.TabContent(tabInfo));
            this.idList.push(tabInfo.id);
            this.tabUL.find("li>a").last().tab("show");
        };
        /**删除标签页 */
        TabPanel.prototype.RemoveTab = function (tabInfo) {
            var idx = this.idList.indexOf(tabInfo.id);
            if (idx >= 0) {
                var $li = this.tabUL.find("li:eq(" + idx + ")");
                var isActive = $li.hasClass("active");
                //移除标签，内容页及id索引
                $li.remove();
                this.$el.find("#" + tabInfo.id).remove(); //移除内容页
                this.idList.splice(idx, 1);
                //如果关闭页是激活页，则激活前一个有效的id
                while (isActive && this.seqList.length > 0) {
                    var lastid = this.seqList.pop();
                    var i = this.idList.indexOf(lastid);
                    if (i >= 0) {
                        this.tabUL.find("li>a").eq(i).tab("show");
                        break;
                    }
                }
            }
        };
        /**全部删除 */
        TabPanel.prototype.RemoveallTab = function () {
            this.init();
            this.bindEvent();
        };
        /*样式添加：外层autotabpanel，标签 tab-tabs  主体页面 tab-content 标签页tab-pane  菜单tab-menus  */
        TabPanel.DefaultClassName = "autotabpanel";
        TabPanel.DefaultEventName = ".autotabpanelEvent";
        TabPanel.OutDom = '<ul class="nav nav-tabs tab-tabs"></ul><div class="tab-content"></div>';
        TabPanel.TabLi = _.template('<li><a href="#<%=id%>" data-toggle="tab" data-id="<%=id%>"><%=title%>&nbsp;<button type="button" class="close" ><span>&times;</span></button></a></li>');
        TabPanel.TabContent = _.template('<div class="tab-pane" id="<%=id%>"><iframe allowfullscreen="" scrolling="auto" style="width:100%;height:100%;" src="<%=url%>" frameborder="0"></iframe></div>');
        TabPanel.TabMenu = "<div class=\"dropdown tab-menus\">\n   <ul class=\"dropdown-menu\">\n    <li><a href=\"#\" data-close=\"me\">\u5173\u95ED</a></li>\n    <li class=\"divider\"></li>\n    <li><a href=\"#\" data-close=\"right\">\u5173\u95ED\u53F3\u4FA7\u6807\u7B7E\u9875</a></li>\n    <li><a href=\"#\" data-close=\"left\">\u5173\u95ED\u5DE6\u4FA7\u6807\u7B7E\u9875</a></li>\n    <li><a href=\"#\" data-close=\"other\">\u5173\u95ED\u5176\u5B83\u6807\u7B7E\u9875</a></li>\n    <li><a href=\"#\" data-close=\"all\">\u5168\u90E8\u5173\u95ED</a></li>\n  </ul>\n</div>";
        return TabPanel;
    }());
    AUTO.TabPanel = TabPanel;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
/*使用说明
全屏支持，需要引入screenfull.js, 页面添加  :-webkit-full-screen { width: 100 %; height: 100 %; }
//element是传入的待全屏的元素，可以是jquery的选择器，或jquery对象。
 $("#divMain").screenfull()  divMain全屏显示,再次执行则取消全屏
另外可以传入true false,指定全屏状态
*/
var AUTO;
(function (AUTO) {
    var ScreenFull = (function () {
        function ScreenFull(element, state) {
            if (screenfull.enabled) {
                if (typeof state == 'undefined') {
                    screenfull.toggle(element);
                }
                else {
                    state && screenfull.request(element);
                    state || screenfull.exit();
                }
            }
            else {
                $.auto.alert("提示", "<p>你的浏览器不支持全屏功能，请你使用较新的浏览器！</p>");
            }
        }
        return ScreenFull;
    }());
    AUTO.ScreenFull = ScreenFull;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
/*使用说明
该功能需要配合SocketData来使用。目前主要功能是ajax请求和广播功能。
1、建立连接  $.auto.setupWS(ip,port)   这会生成$.auto.ws变量
2、代替jax请求  $.auto.ajax(url,{data:d}).done(function(){});
3、广播功能:$.auto.join("room",function(){房间内有消息执行});
            $.auto.leave("room");
            $.auto.broadcast("room",data);  广播数据可能 是字符串或对象
*/
var AUTO;
(function (AUTO) {
    var AUTOWEBSOCKET = (function () {
        function AUTOWEBSOCKET(ip, port) {
            this.ident_id = 0; //每次请求，都增加一次，表示页面请求计数。返回时，也靠它来找到方法。
            this.defferd_map = {}; //消息的延迟map，一个deffer只能用一次
            this.cb_map = {}; //回调map，绑定函数，可以执行多次
            var scope = this;
            try {
                this.ws = new WebSocket("ws://" + ip + ":" + port);
                this.ws.onmessage = this.onmessage.bind(this);
                this.ws.onerror = this.onerror.bind(this);
                this.ws.onclose = this.onclose.bind(this);
            }
            catch (e) {
                this.ws = null;
            }
        }
        AUTOWEBSOCKET.prototype.onmessage = function (msg) {
            //返回数据增加RESULT字段，是实际响应数据
            var data = JSON.parse(msg.data);
            if (data._ident_id) {
                //如果是ajax的消息
                var id = data._ident_id;
                var def = this.defferd_map[id];
                if (data._exception)
                    def.reject(data._exception);
                else
                    def.resolve(data._data);
            }
            else if (data._room) {
                //如果是房间（广播）消息
                var room = data._room;
                this.cb_map[room] && this.cb_map[room](data._data);
            }
        };
        AUTOWEBSOCKET.prototype.onerror = function (ev) {
            console.log("错误提示", "系统连接WebSocket服务时，发生异常！");
        };
        AUTOWEBSOCKET.prototype.onclose = function (ev) {
            console.log("提示", "系统已经断开WebSocket服务连接！");
        };
        AUTOWEBSOCKET.prototype.support = function () {
            if (!this.ws)
                console.log("浏览器不支持WebSocket!");
            return false;
        };
        //防止正在连接中，需要延迟发送
        AUTOWEBSOCKET.prototype.send = function (content) {
            var scope = this;
            if (this.ws.readyState == this.ws.CONNECTING) {
                setTimeout(function () { scope.send(content); }, 500);
            }
            else if (this.ws.readyState == this.ws.OPEN) {
                this.ws.send(content);
            }
        };
        //请求及返回时，都要带着_requestpath  _ident_id的参数
        //返回一个def，
        //setting的属性只使用data一个，这里使用JQueryAjaxSettings，目的是替代时，不报ts错误。
        AUTOWEBSOCKET.prototype.ajax = function (url, setting) {
            if (!this.support())
                return $.Deferred();
            //url 必须是/api/control/action 格式  替换，然后把第一个空值去掉
            url = url.replace(/\\/g, '/');
            var para = url.split("/");
            para[0] || para.shift();
            //为id生成一个$.defer,保存起来
            var def = $.Deferred();
            this.defferd_map[++this.ident_id] = def;
            //发送请求
            var data = {
                _requestpath: para[1] + "/" + para[2],
                _data: setting.data,
                _ident_id: this.ident_id
            };
            this.send("api" + " " + JSON.stringify(data));
            return def.promise();
        };
        //加入一个房间，相当于订阅一下。
        //暂时不增加事件链了。这样一个房间只有一个消息
        AUTOWEBSOCKET.prototype.join = function (room, onRoomMsg) {
            if (!this.support())
                return;
            this.cb_map[room] = onRoomMsg;
            var msg = { _room: room, _leave: 0 };
            this.send("join " + JSON.stringify(msg));
        };
        //离开一个房间
        AUTOWEBSOCKET.prototype.leave = function (room) {
            if (!this.support())
                return;
            var msg = { _room: room, _leave: 1 };
            this.send("join " + JSON.stringify(msg));
            delete this.cb_map[room];
        };
        //向房间内发布一个信息
        AUTOWEBSOCKET.prototype.broadcast = function (room, data) {
            if (!this.support())
                return;
            var msg = { _room: room, _data: data };
            this.send("broadcast " + JSON.stringify(msg));
        };
        return AUTOWEBSOCKET;
    }());
    AUTO.AUTOWEBSOCKET = AUTOWEBSOCKET;
})(AUTO || (AUTO = {}));
///<reference path="../typings/tsd.d.ts" />
var AUTO;
(function (AUTO) {
    /**文件ajax自动上传，带滚动，取消等功能，支持ie10+  */
    var AutoFileUploader = (function () {
        function AutoFileUploader(element, option) {
            /*是否正在上传*/
            this.isUping = false;
            this._opt = {
                url: '', text: '选择上传', filter: ''
            };
            var scope = this;
            this.$file = $(element);
            this._opt = $.extend(this._opt, option);
            if (!this.$file.parent().hasClass(AutoFileUploader.DefaultClassName)) {
                this.$file.wrap($("<div class='" + AutoFileUploader.DefaultClassName + "'>"));
                this.$file.before("<span class=\"btn btn-default btn-sm autoFuText\">" + this._opt.text + "</span>");
            }
            else {
                this.$file.off(AutoFileUploader.DefaultEventNamespace);
                this.$file.prev().text(this._opt.text);
            }
            if (!this.isSupport())
                this.$file.prop("disabled", "disabled").attr("title", '当前浏览器不支持HTML5上传！')
                    .prev().attr({ "disabled": "disabled" });
            this.bindEvent();
        }
        /**是否支持上传*/
        AutoFileUploader.prototype.isSupport = function () {
            return !!window["FormData"] &&
                !!$.ajaxSettings.xhr().upload;
        };
        /*执行校验后缀*/
        AutoFileUploader.prototype.CheckFile = function (filename) {
            return !this._opt.filter || new RegExp("(" + this._opt.filter + ")$").test(filename);
        };
        AutoFileUploader.prototype.bindEvent = function () {
            var scope = this;
            this.$file.on("change" + AutoFileUploader.DefaultEventNamespace, scope.upload.bind(scope));
            this.$file.on("click" + AutoFileUploader.DefaultEventNamespace, function () {
                /**判断状态*/
                if (scope.isUping) {
                    scope.xhr.abort();
                    scope.$file.prev().css("background", "#fff").text(scope._opt.text);
                    scope.isUping = false;
                    scope.$file.trigger("canceled");
                    return false;
                }
            });
        };
        /**执行上传 */
        AutoFileUploader.prototype.upload = function () {
            var scope = this;
            var files = this.$file.prop("files");
            //如果没有文件，或者没通过验证后缀
            if (!files.length)
                return;
            if (_.some(files, function (f) {
                if (!scope.CheckFile(f.name)) {
                    console.log(f.name + "文件格式不正确！");
                    scope.$file.trigger("error", f.name);
                    return true;
                }
            })) {
                return;
            }
            var fd = new FormData();
            fd.append("_file", files[0]);
            scope.isUping = true;
            $.ajax(this._opt.url, {
                data: fd,
                processData: false,
                type: "POST", contentType: false, dataType: 'json',
                xhr: function () {
                    scope.xhr = $.ajaxSettings.xhr();
                    if (scope.xhr.upload) {
                        scope.xhr.upload.addEventListener("progress", function (e) {
                            var per = Math.round((e.loaded / e.total) * 100) + "%";
                            scope.$file.prev().css("background", "linear-gradient(to right, #5cb85c " + per + ",#fff 0)").text("取消");
                        }, false);
                        scope.xhr.upload.addEventListener("loadend", function (e) {
                            scope.$file.prev().css("background", "#fff").text(scope._opt.text);
                            scope.isUping = false;
                        }, false);
                    }
                    return scope.xhr;
                }
            }).done(function (ret) {
                scope.$file.trigger("done", ret);
            }).fail(function () {
                console.log("上传时错误！");
                scope.$file.trigger("error", "上传时错误");
                return true;
            });
        };
        AutoFileUploader.DefaultClassName = "autoFu";
        AutoFileUploader.DefaultEventNamespace = ".autoFuEvent";
        return AutoFileUploader;
    }());
    AUTO.AutoFileUploader = AutoFileUploader;
})(AUTO || (AUTO = {}));
/*
Auto.JS之Typescript重写。
从2013底开始，在老采油工程升级、中原老分公司报表查询，中原区块管理（未用）这几个项目开发中，逐步实现了一些功能函数，
截止2015.7月，已包含日期控件、表格控件，弹出窗口，图表可视化等等！
原项目文件越来越大，难于模块化管理；在代码组织上，我对autotable的写法也一直想重构！自己也要学习一下新东西
总之Typescript是一个不错的入口，支持模块管理、强类型、ES6的许多特性。
IE9已完整支持ES5。
jquery3不兼容datepicker插件
*/
///<reference path="../typings/tsd.d.ts" />
///<reference path="dialog.ts" />
///<reference path="datebox.ts" />
///<reference path="selectword.ts" />
///<reference path="ajaxbutton_autotimer.ts" />
///<reference path="autotable.ts" />
///<reference path="autoform.ts" />
/// <reference path="tabpanel.ts" />
/// <reference path="autofullscreen.ts" />
/// <reference path="autowebsocket.ts" />
/// <reference path="autofileuploader.ts" />
(function ($, global) {
    'use strict';
    $.auto = {};
    //日期格式化 
    $.auto.frmDate = function (date, fmt) {
        var o = {
            "M+": date.getMonth() + 1,
            "d+": date.getDate(),
            "h+": date.getHours(),
            "m+": date.getMinutes(),
            "s+": date.getSeconds(),
            "q+": Math.floor((date.getMonth() + 3) / 3),
            "S": date.getMilliseconds() //毫秒
        };
        if (/(y+)/.test(fmt))
            fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt))
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    };
    //弹窗
    $.auto.alert = function (title, msg, option) {
        var opt = $.extend({ title: title }, option);
        layer.alert(msg, opt);
    };
    $.auto.confirm = function (title, msg, yes, cancel) {
        layer.confirm(msg, { title: title }, function (index) {
            yes && yes();
            layer.close(index);
        }, function (index) {
            cancel && cancel();
            layer.close(index);
        });
    };
    //本地存储
    var wls = window.localStorage;
    $.auto.storage = {
        //不存在，返回null
        get: function (key) {
            if (wls) {
                var str = wls.getItem(key);
                try {
                    return JSON.parse(str);
                }
                catch (e) {
                    return str;
                }
            }
        },
        set: function (key, value) {
            if (wls) {
                return wls.setItem(key, _.isString(value) ? value : JSON.stringify(value));
            }
        }
    };
    //修正js中浮点数运算时产生精度误差，只保留最大精度,
    //t ,m 用于保留精度。 s是数字的字符串，p是.的位置  r是结果
    $.extend($.auto, {
        div: function () {
            if (arguments.length == 1) {
                return parseFloat(arguments[0]);
            }
            else {
                var t, m, s, p, r = arguments[0];
                s = arguments[0].toString();
                p = s.indexOf(".");
                m = (p > -1) ? (s.length - p - 1) : 0;
                for (var i = 1; i < arguments.length; i++) {
                    s = arguments[i].toString();
                    p = s.indexOf(".");
                    t = (p > -1) ? (s.length - p - 1) : 0;
                    m = t > m ? t : m;
                    r /= (parseFloat(arguments[i]));
                }
                return Number(r.toFixed(m));
            }
        },
        mul: function () {
            if (arguments.length == 1) {
                return parseFloat(arguments[0]);
            }
            else {
                var t = 0, m = 0, s, p, r = 1;
                for (var i = 0; i < arguments.length; i++) {
                    s = arguments[i].toString();
                    p = s.indexOf(".");
                    t = (p > -1) ? (s.length - p - 1) : 0;
                    m += t;
                    r *= parseFloat(arguments[i]);
                }
                return Number(r.toFixed(m));
            }
        },
        add: function () {
            if (arguments.length == 1) {
                return parseFloat(arguments[0]);
            }
            else {
                var t = 0, m = 0, s, p, r = 0;
                for (var i = 0; i < arguments.length; i++) {
                    s = arguments[i].toString();
                    p = s.indexOf(".");
                    t = (p > -1) ? (s.length - p - 1) : 0;
                    m = t > m ? t : m;
                    r += parseFloat(arguments[i]);
                }
                return Number(r.toFixed(m));
            }
        },
        sub: function () {
            if (arguments.length == 1) {
                return parseFloat(arguments[0]);
            }
            else {
                var t, m, s, p, r = arguments[0];
                s = arguments[0].toString();
                p = s.indexOf(".");
                m = (p > -1) ? (s.length - p - 1) : 0;
                for (var i = 1; i < arguments.length; i++) {
                    s = arguments[i].toString();
                    p = s.indexOf(".");
                    t = (p > -1) ? (s.length - p - 1) : 0;
                    m = t > m ? t : m;
                    r -= parseFloat((arguments[i]));
                }
                return Number(r.toFixed(m));
            }
        }
    });
    //缓存get请求结果
    /* $.auto.memoryget=_.memoize(function(url,data){
         return $.getJSON(url, data);
     });*/
    $.auto.memoryget = _.memoize($.get, function () {
        return JSON.stringify(arguments);
    });
    //dialog
    $.fn["dialog"] = function (options) {
        return this.each(function () {
            new AUTO.Dialog(this, options);
        });
    };
    $.fn["autoDate"] = function (mode, options) {
        return this.each(function () {
            new AUTO.DateBox(this, mode.toLowerCase(), options);
        });
    };
    $.fn["selectWord"] = function () {
        return this.each(function () {
            new AUTO.SelectWord(this);
        });
    };
    $.fn["autoTable"] = function (options) {
        if (options == "option") {
            return $(this).data("OriginData");
        }
        else {
            return this.each(function () {
                new AUTO.AutoTable(this, options);
            });
        }
    };
    $.fn["autoTimer"] = function (options) {
        return this.each(function () {
            new AUTO.AutoTimer(this, options);
        });
    };
    $.fn["ajaxButton"] = function (fun_def, fun_para) {
        return this.each(function () {
            new AUTO.AjaxButton(this, fun_def, fun_para);
        });
    };
    $.fn["tabpanel"] = function (cmd, tabInfo) {
        return this.each(function () {
            new AUTO.TabPanel(this, cmd, tabInfo);
        });
    };
    $.fn["autoForm"] = function (option) {
        return this.each(function () {
            new AUTO.AutoForm(this, option);
        });
    };
    $.fn["screenfull"] = function (state) {
        return this.each(function () {
            new AUTO.ScreenFull(this, state);
        });
    };
    $.fn["autoFileUploader"] = function (option) {
        return this.each(function () {
            new AUTO.AutoFileUploader(this, option);
        });
    };
    $.auto.setupWS = function (ip, port) { $.auto.ws = new AUTO.AUTOWEBSOCKET(ip, port); };
    $.auto.ajax = function (url, setting) {
        return $.auto.ws.ajax(url, setting);
    };
    $.auto.join = function (room, onRoomMsg) {
        $.auto.ws.join(room, onRoomMsg);
    };
    $.auto.leave = function (room) {
        $.auto.ws.leave(room);
    };
    $.auto.broadcast = function (room, data) {
        $.auto.ws.broadcast(room, data);
    };
})($, window);
